home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / xulrunner / python / BitTorrent / Rerequester.py < prev    next >
Encoding:
Python Source  |  2007-11-12  |  5.6 KB  |  154 lines

  1. # Written by Bram Cohen
  2. # see LICENSE.txt for license information
  3.  
  4. from zurllib import urlopen, quote
  5. from btformats import check_peers
  6. from bencode import bdecode
  7. from threading import Thread, Lock
  8. from socket import error
  9. from time import time
  10. from random import randrange
  11. from binascii import b2a_hex
  12.  
  13. class Rerequester:
  14.     def __init__(self, url, interval, sched, howmany, minpeers, 
  15.             connect, externalsched, amount_left, up, down,
  16.             port, ip, myid, infohash, timeout, errorfunc, maxpeers, doneflag,
  17.             upratefunc, downratefunc, ever_got_incoming):
  18.         self.url = ('%s?info_hash=%s&peer_id=%s&port=%s&key=%s' %
  19.             (url, quote(infohash), quote(myid), str(port),
  20.             b2a_hex(''.join([chr(randrange(256)) for i in xrange(4)]))))
  21.         if ip != '':
  22.             self.url += '&ip=' + quote(ip)
  23.         self.interval = interval
  24.         self.last = None
  25.         self.trackerid = None
  26.         self.announce_interval = 30 * 60
  27.         self.sched = sched
  28.         self.howmany = howmany
  29.         self.minpeers = minpeers
  30.         self.connect = connect
  31.         self.externalsched = externalsched
  32.         self.amount_left = amount_left
  33.         self.up = up
  34.         self.down = down
  35.         self.timeout = timeout
  36.         self.errorfunc = errorfunc
  37.         self.maxpeers = maxpeers
  38.         self.doneflag = doneflag
  39.         self.upratefunc = upratefunc
  40.         self.downratefunc = downratefunc
  41.         self.ever_got_incoming = ever_got_incoming
  42.         self.last_failed = True
  43.         self.last_time = 0
  44.  
  45.     def c(self):
  46.         self.sched(self.c, self.interval)
  47.         if self.ever_got_incoming():
  48.             getmore = self.howmany() <= self.minpeers / 3
  49.         else:
  50.             getmore = self.howmany() < self.minpeers
  51.         if getmore or time() - self.last_time > self.announce_interval:
  52.             self.announce()
  53.  
  54.     def begin(self):
  55.         self.sched(self.c, self.interval)
  56.         self.announce(0)
  57.  
  58.     def announce(self, event = None):
  59.         self.last_time = time()
  60.         s = ('%s&uploaded=%s&downloaded=%s&left=%s' %
  61.             (self.url, str(self.up()), str(self.down()), 
  62.             str(self.amount_left())))
  63.         if self.last is not None:
  64.             s += '&last=' + quote(str(self.last))
  65.         if self.trackerid is not None:
  66.             s += '&trackerid=' + quote(str(self.trackerid))
  67.         if self.howmany() >= self.maxpeers:
  68.             s += '&numwant=0'
  69.         else:
  70.             s += '&compact=1'
  71.         if event != None:
  72.             s += '&event=' + ['started', 'completed', 'stopped'][event]
  73.         set = SetOnce().set
  74.         def checkfail(self = self, set = set):
  75.             if set():
  76.                 if self.last_failed and self.upratefunc() < 100 and self.downratefunc() < 100:
  77.                     self.errorfunc('Problem connecting to tracker - timeout exceeded')
  78.                 self.last_failed = True
  79.         self.sched(checkfail, self.timeout)
  80.         t = Thread(target = self.rerequest, args = [s, set], 
  81.             name = "BitTorrent -- rerequest")
  82.         t.setDaemon(True)
  83.         t.start()
  84.  
  85.     def rerequest(self, url, set):
  86.         try:
  87.             h = urlopen(url)
  88.             r = h.read()
  89.             h.close()
  90.             if set():
  91.                 def add(self = self, r = r):
  92.                     self.last_failed = False
  93.                     self.postrequest(r)
  94.                 self.externalsched(add, 0)
  95.         except (IOError, error), e:
  96.             if set():
  97.                 def fail(self = self, r = 'Problem connecting to tracker - ' + str(e)):
  98.                     if self.last_failed:
  99.                         self.errorfunc(r)
  100.                     self.last_failed = True
  101.                 self.externalsched(fail, 0)
  102.  
  103.     def postrequest(self, data):
  104.         try:
  105.             r = bdecode(data)
  106.             check_peers(r)
  107.             if r.has_key('failure reason'):
  108.                 self.errorfunc('rejected by tracker - ' + r['failure reason'])
  109.             else:
  110.                 if r.has_key('warning message'):
  111.                     self.errorfunc('warning from tracker - ' + r['warning message'])
  112.                 self.announce_interval = r.get('interval', self.announce_interval)
  113.                 self.interval = r.get('min interval', self.interval)
  114.                 self.trackerid = r.get('tracker id', self.trackerid)
  115.                 self.last = r.get('last')
  116.                 p = r['peers']
  117.                 peers = []
  118.                 if type(p) == type(''):
  119.                     for x in xrange(0, len(p), 6):
  120.                         ip = '.'.join([str(ord(i)) for i in p[x:x+4]])
  121.                         port = (ord(p[x+4]) << 8) | ord(p[x+5])
  122.                         peers.append((ip, port, None))
  123.                 else:
  124.                     for x in p:
  125.                         peers.append((x['ip'], x['port'], x.get('peer id')))
  126.                 ps = len(peers) + self.howmany()
  127.                 if ps < self.maxpeers:
  128.                     if self.doneflag.isSet():
  129.                         if r.get('num peers', 1000) - r.get('done peers', 0) > ps * 1.2:
  130.                             self.last = None
  131.                     else:
  132.                         if r.get('num peers', 1000) > ps * 1.2:
  133.                             self.last = None
  134.                 for x in peers:
  135.                     self.connect((x[0], x[1]), x[2])
  136.         except ValueError, e:
  137.             if data != '':
  138.                 self.errorfunc('bad data from tracker - ' + str(e))
  139.  
  140. class SetOnce:
  141.     def __init__(self):
  142.         self.lock = Lock()
  143.         self.first = True
  144.  
  145.     def set(self):
  146.         try:
  147.             self.lock.acquire()
  148.             r = self.first
  149.             self.first = False
  150.             return r
  151.         finally:
  152.             self.lock.release()
  153.  
  154.